﻿#region Copyright
//***************************************************************************************
//                              This module is part of the 
//                                  GreenPoint Package
//                                     developeb by
//                                      Green Team
//***************************************************************************************
//
//   PROJECT NAME:    GreenTeam.SharePoint.
//   AUTHOR:          Claudio Brotto.
//   CONTACTS:        mailto: cbrotto@greenteam.it
//                    www.greenteam.it
//   REFERENCES:      n/a.
//
//=======================================================================================
//
//   HISTORY: 
//   --------
//    
//   --------------------------------------------------------------------------------
//  |  #  |   Date   |    Author    |                   Reason                       |
//  |-----|----------|--------------|------------------------------------------------|
//  |  1  | --/--/-- | C. Brotto    | Original release.                              |
//   --------------------------------------------------------------------------------
//
//=======================================================================================
//
//   LICENSE (Microsoft Public License - Ms-PL)
//   ------------------------------------------
// 
// This license governs use of the accompanying software. If you use the software, you 
// accept this license. If you do not accept the license, do not use the software.
// 1. Definitions
// The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have 
// the same meaning here as under U.S. copyright law.
// A “contribution” is the original software, or any additions or changes to the 
// software.
// A “contributor” is any person that distributes its contribution under this license.
// “Licensed patents” are a contributor’s patent claims that read directly on its 
// contribution.
// 
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license, including the license 
// conditions and limitations in section 3, each contributor grants you a non-exclusive, 
// worldwide, royalty-free copyright license to reproduce its contribution, 
// prepare derivative works of its contribution, and distribute its contribution or any 
// derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license, including the license 
// conditions and limitations in section 3, each contributor grants you a non-exclusive, 
// worldwide, royalty-free license under its licensed patents to make, have made, use, 
// sell, offer for sale, import, and/or otherwise dispose of its contribution in the 
// software or derivative works of the contribution in the software.
// 
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you rights to use any 
// contributors’ name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over patents that you claim 
// are infringed by the software, your patent license from such contributor to the 
// software ends automatically.
// (C) If you distribute any portion of the software, you must retain all copyright, 
// patent, trademark, and attribution notices that are present in the software.
// (D) If you distribute any portion of the software in source code form, you may do so 
// only under this license by including a complete copy of this license with your 
// distribution. If you distribute any portion of the software in compiled or object code 
// form, you may only do so under a license that complies with this license.
// (E) The software is licensed “as-is.” You bear the risk of using it. The contributors 
// give no express warranties, guarantees or conditions. You may have additional consumer 
// rights under your local laws which this license cannot change. To the extent permitted 
// under your local laws, the contributors exclude the implied warranties of 
// merchantability, fitness for a particular purpose and non-infringement.
// 
//***************************************************************************************
#endregion

#region Code
namespace GreenPoint.StsAdmExtensions
{
  #region using Directives
  using Microsoft.SharePoint;
  using Microsoft.SharePoint.StsAdmin;
  using System;
  using System.Collections.Specialized;
  using System.Linq;
  using System.Reflection;
  using System.Text;
  using System.Xml;
  using System.Xml.Linq;
  using System.IO;
  #endregion

  #region GetStorageAllocation Extension Class
  /// <summary>
  /// 
  /// </summary>
  public class GetStorageAllocation : ISPStsadmCommand
  {

    #region Accumulators
    /// <summary>
    /// Total bytes count for documents allocation.
    /// </summary>
    private Int64 totalStorageAllocation = 0;

    /// <summary>
    /// Total files count.
    /// </summary>
    private Int32 totalFileCount = 0;
    #endregion

    #region ISPStsadmCommand Members
    /// <summary>
    /// Disply an help message to the requesting user.
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    public String GetHelpMessage(String command)
    {
      StringBuilder helpMessageBuilder = GetUsageString();
      return helpMessageBuilder.ToString();
    }

    /// <summary>
    /// The main execution path for the extension command.
    /// </summary>
    /// <param name="command">The name of the extension command</param>
    /// <param name="keyValues">The dictionary of all command parameters</param>
    /// <param name="output">The output returned to the user</param>
    /// <returns></returns>
    public Int32 Run(String command, StringDictionary keyValues, out String output)
    {
      // Clean output.
      output = String.Empty;
      
      // Mark this as the starting point.
      DateTime startTime = DateTime.Now;
      
      // Pick up parameters.
      String webUrl = keyValues["url"];
      String userName = keyValues["user"];
      String outputFile = keyValues["outputFile"];

      // Ensure Parameters.
      String errorMessage;
      if (!EnsureParameters(webUrl, userName, outputFile, out errorMessage))
      {        
        output = 
          errorMessage + 
          Environment.NewLine + 
          this.GetUsageString().ToString();
        return 0;
      }

      // Prepare the output structure (XML fragment).
      XElement rootElement = new XElement(
        "Allocation",
        new XAttribute("Web", webUrl),
        new XAttribute("User", String.IsNullOrEmpty(userName) ? "none" : userName));

      // Extract all information.
      using (SPSite site = new SPSite(webUrl))
      {
        using (SPWeb web = site.OpenWeb())
        {
          DumpWeb(rootElement, web, userName);
        }
      }

      // Add global allocation data.
      rootElement.Add(
        new XAttribute("Space", totalStorageAllocation),
        new XAttribute("Files", totalFileCount));

      // Dump results.
      Console.WriteLine(rootElement.ToString());
      WriteOutputFile(rootElement, outputFile);
      output = "The query completed in " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString() + " second(s)";
      return 0;
    }
    #endregion

    #region Logics
    /// <summary>
    /// Display some details about the command usage.
    /// </summary>
    /// <returns></returns>
    private StringBuilder GetUsageString()
    {
      StringBuilder helpMessageBuilder = new StringBuilder();
      helpMessageBuilder.AppendLine(@"");
      helpMessageBuilder.AppendLine(@"GREENPOINT Extensions: Get Storage Allocation");
      helpMessageBuilder.AppendLine(@"(Display the storage space for the specified files)");
      helpMessageBuilder.AppendLine(@"");
      helpMessageBuilder.AppendLine(@"Parameters:");
      helpMessageBuilder.AppendLine(@"  -url (the url of the web site)");
      helpMessageBuilder.AppendLine(@"  [-user] (a string which contains the user display name)");
      helpMessageBuilder.AppendLine(@"  [-outputFile] (the file you want your output to be stored in)");
      return helpMessageBuilder;
    }

    /// <summary>
    /// Validate input parameters.
    /// </summary>
    /// <param name="webUrl"></param>
    /// <param name="userName"></param>
    /// <param name="outputFile"></param>
    /// <returns></returns>
    private Boolean EnsureParameters(String webUrl, String userName, String outputFile, out String errorMessage)
    {
      Boolean validated = false;
      errorMessage = String.Empty;
      
      // Ensure the web parameter is valid.
      // Just try to open it, no need to loop through the farm objects 
      // since performance is not an issue here.
      if (!String.IsNullOrEmpty(webUrl))
      {
        try
        {
          using (SPSite requiredSite = new SPSite(webUrl))
          {
            using (SPWeb requiredWeb = requiredSite.OpenWeb())
            {
              validated = true;
            }
          }
        }
        catch (Exception exc)
        {
          errorMessage = exc.Message;
        }
      }
      else
      {
        errorMessage = "No web url is specified";
      }

      return validated;
    }

    /// <summary>
    /// Process the specified web site.
    /// </summary>
    /// <param name="outputBuilder"></param>
    /// <param name="web"></param>
    private void DumpWeb(XElement parentElement, SPWeb web, String user)
    {
      // Create the web element.
      XElement webElement = new XElement(
        "Web",
        new XAttribute("Title", web.Title),
        new XAttribute("Url", web.Url));

      // Initialize allocation counters.
      Int64 webStorageAllocation = 0;
      Int32 webFileCount = 0;
      
      // Loop through document libraries and compute specific allocations.
      foreach (SPList list in web.Lists)
      {
        SPDocumentLibrary library = list as SPDocumentLibrary;
        if (library != null)
        {
          Int64 libraryStorageAllocation = 0;
          Int32 libraryFileCount = 0;
          foreach (SPListItem item in library.Items)
          {
            SPFile file = item.File;
            String userNameInItem = item["Created By"] as String; // Fix this for language-specifics.
            if (String.IsNullOrEmpty(user) || (userNameInItem.ToLower().Contains(user.ToLower())))
            {
              if (file != null)
              {
                Int64 fileSize = file.Length;
                libraryStorageAllocation += fileSize;
                libraryFileCount++;
                webStorageAllocation += fileSize;
                webFileCount++;
                totalStorageAllocation += fileSize;
                totalFileCount++;
              }
            }
          }
          XElement listElement = new XElement(
            "List",
            new XAttribute("Name", library.Title),
            new XAttribute("Space", libraryStorageAllocation),
            new XAttribute("Files", libraryFileCount));
          webElement.Add(listElement);
        }
      }
      webElement.Add(
        new XAttribute("Space", webStorageAllocation),
        new XAttribute("Files", webFileCount));

      // Add web data to the parent node.
      parentElement.Add(webElement);
      
      // Dump children.
      foreach (SPWeb subWeb in web.Webs)
      {
        DumpWeb(webElement, subWeb, user);
      }
    }

    /// <summary>
    /// Dump the XML results to the user specified file.
    /// </summary>
    /// <param name="rootElement"></param>
    /// <param name="outputFile"></param>
    private void WriteOutputFile(XElement rootElement, String outputFile)
    {
      try
      {
        using (XmlWriter outputWriter = XmlWriter.Create(outputFile))
        {
          rootElement.WriteTo(outputWriter);
        }
      }
      catch 
      {
        Console.WriteLine("Errors occurred while writing the command output to " + outputFile);
      }
    }
    #endregion
  }
  #endregion
}
#endregion